package com.ffly.astar;

import java.util.List;

import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;

public class MainActivity extends Activity implements SurfaceHolder.Callback,
		OnClickListener {

	enum MODE{
		NORMAL,
		START,
		END,
		WALL
	}
	
	SurfaceView mSurfaceView;
	//触摸的X坐标
	float mTouchX = 0;
	//触摸的Y坐标
	float mTouchY = 0;
	//画布宽度
	int mWidth = 0;
	//画布高度
	int mHeight = 0;
	//格子宽度
	int mCellW = 0;
	//格子高度
	int mCellH = 0;
	//画布左右间距
	int mPaddingX = 0;
	//画布上下间距
	int mPaddingY = 0;
	//当前编辑模式
	MODE mEditMode = MODE.NORMAL;
	//起点位置
	TwoValue<Integer, Integer> mStart;
	//终点位置
	TwoValue<Integer, Integer> mEnd;
	
	//寻路
	AStar mAStar = new AStar();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		findViewById(R.id.id_end).setOnClickListener(this);
		findViewById(R.id.id_start).setOnClickListener(this);
		findViewById(R.id.id_wall).setOnClickListener(this);
		findViewById(R.id.id_clear_wall).setOnClickListener(this);
		findViewById(R.id.id_setting).setOnClickListener(this);
		
		mSurfaceView = (SurfaceView) findViewById(R.id.id_surfaceview);
		mSurfaceView.getHolder().addCallback(this);
		mSurfaceView.setOnTouchListener(new OnTouchListener() {
			//画布触摸事件监听
			@Override
			public boolean onTouch(View view, MotionEvent event) {
				int action = event.getAction();
				if (action == MotionEvent.ACTION_UP) {
					mTouchX = event.getX();
					mTouchY = event.getY();
					
					
					TwoValue<Integer, Integer> point = touch2Point(mTouchX,
							mTouchY);
					mAStar.isRun = false;
					if (mEditMode == MODE.WALL) {
						// 起点不能被设置成墙体
						if (mStart != null && mStart.first == point.first
								&& mStart.second == point.second)
							return false;
						// 目标点不能被设置为墙体
						if (mEnd != null && mEnd.first == point.first
								&& mEnd.second == point.second)
							return false;
						
						// 设置墙体标示
						mAStar.setWall(point.first, point.second);
						
					} else if (mEditMode == MODE.START
							&& !mAStar.isWall(point.first,point.second)) {
						// 设置起点
						mStart = point;
					} else if (mEditMode == MODE.END
							&& !mAStar.isWall(point.first,point.second)) {
						// 设置目标点
						mEnd = point;
					}
					synchronized (mDrawFrameThreadRunnable) {
						// 触发surfaceview刷新
						mDrawFrameThreadRunnable.notifyAll();
					}
				}
				return false;
			}
		});
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		mWidth = width;
		mHeight = height;
		mCellW = mWidth / Params.COL;
		mCellH = mHeight / Params.ROW;
		mPaddingX = (mWidth - mCellW * Params.COL) / 2;
		mPaddingY = (mHeight - mCellH * Params.ROW) / 2;
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		//开启绘图线程
		new Thread(mDrawFrameThreadRunnable).start();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {

	}

	/**
	 * 绘图线程控制
	 */
	Runnable mDrawFrameThreadRunnable = new Runnable() {

		@Override
		public void run() {
			Paint p = new Paint();
			
			
			while (true) {
				synchronized (this) {
					try {
						//没有新的改变时，挂起线程
						this.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
						break;
					}

					//设置起点
					if (mStart != null) {
						mAStar.setStartPoint(mStart.first, mStart.second);
					}
					//设置终点
					if (mEnd != null) {
						mAStar.setEndPoint(mEnd.first, mEnd.second);
					}
					
					//计算路径
					List<TwoValue<Integer, Integer>> paths = null;
					if (mStart != null && mEnd != null) {
						paths = mAStar.runLogic();
					}
					
					
					//================ 绘图 =====================
					Canvas canvas = mSurfaceView.getHolder().lockCanvas();
					//绘制背景
					canvas.drawARGB(0xff, 0xcd, 0xcd, 0xcd);
					//绘制网格
					drawGrid(canvas, p);
					//绘制墙体
					drawWall(canvas,p);
					//绘制起点
					if(mStart != null){
						p.setColor(Color.LTGRAY);
						drawPointDot(canvas,mStart.first,mStart.second,p);
					}
					//绘制终点
					if(mEnd != null){
						p.setColor(Color.YELLOW);
						drawPointDot(canvas,mEnd.first,mEnd.second,p);
					}
					//绘制路径结果
					if(paths != null){
						p.setColor(Color.GREEN);
						for(TwoValue<Integer, Integer> path : paths){
							drawPointDot(canvas,path.first,path.second,p);
						}
					}
					
					mSurfaceView.getHolder().unlockCanvasAndPost(canvas);
				}

			}
		}
	};

	/**
	 * 绘制网格
	 * @param canvas
	 * @param p
	 */
	void drawGrid(Canvas canvas, Paint p) {
		p.setColor(Color.BLACK);
		canvas.drawRect(mPaddingX, mPaddingY, mWidth - mPaddingX, mHeight
				- mPaddingY, p);
		p.setColor(Color.RED);
		for(int i = 0;i<Params.ROW;i++){
			canvas.drawLine(mPaddingX, mPaddingY+i*mCellH, mWidth-mPaddingX, mPaddingY+i*mCellH, p);
		}
		
		for (int j = 0; j < Params.COL; j++) {
			canvas.drawLine(mPaddingX+j*mCellW, mPaddingY, mPaddingX+j*mCellW, mHeight - mPaddingY, p);
		}
	}
	
	/**
	 * 在触摸的位置，绘制一个方块
	 * @param canvas
	 * @param x
	 * @param y
	 * @param p
	 */
	void drawTouchDot(Canvas canvas,float x,float y,Paint p){
		Rect rect = touch2Rect(x,y);
		canvas.drawRect(rect, p);
	}
	
	/**
	 * 在指定的行列中绘制方块
	 * @param canvas
	 * @param x
	 * @param y
	 * @param p
	 */
	void drawPointDot(Canvas canvas,int x,int y,Paint p){
		Rect rect = point2Rect(x, y);
		rect.left += 1;
		rect.right -= 1;
		rect.top += 1;
		rect.bottom -= 1;
		canvas.drawRect(rect, p);
	}
	
	/**
	 * 绘制墙体
	 * @param canvas
	 * @param p
	 */
	void drawWall(Canvas canvas,Paint p){
		p.setColor(Color.BLUE);
		for(int y=0;y<Params.ROW;y++){
			for(int x=0;x<Params.COL;x++){
				if(mAStar.isWall(x, y)){
					drawPointDot(canvas, x, y, p);
				}
			}
		}
	}
	
	
	Rect touch2Rect(float x, float y) {
		TwoValue<Integer, Integer> tv = touch2Point(x, y);
		int a = tv.first * mCellW + mPaddingX;
		int b = tv.second * mCellH + mPaddingY;
		return new Rect(a, b, a + mCellW, b + mCellH);
	}
	
	Rect point2Rect(int x, int y) {
		int a = x * mCellW + mPaddingX;
		int b = y * mCellH + mPaddingY;
		return new Rect(a, b, a + mCellW, b + mCellH);
	}
	
	TwoValue<Integer, Integer> touch2Point(float x, float y) {
		int f = (int) ((x - mPaddingX) / mCellW);
		int s = (int) ((y - mPaddingY) / mCellH);
		return new TwoValue<Integer, Integer>(f, s);
	}
	

	@Override
	public void onClick(View view) {
		switch (view.getId()) {
		case R.id.id_end:
			mEditMode = MODE.END;
			mEnd = null;
			break;
		case R.id.id_start:
			mStart = null;
			mEditMode = MODE.START;
			break;
		case R.id.id_setting:
			break;
		case R.id.id_wall:
			mEnd = null;
			mEditMode = MODE.WALL;
			break;
		case R.id.id_clear_wall:
			mAStar.reset();
			mEnd = null;
			break;
		default:
			break;
		}
	}
}